<?php

/**
 * 程序管理 - 控制器类
 * 
 * @package    01CMS
 * @subpackage admin
 * @author     rolong at vip.qq.com
 * @version    1.0.0
 * @link       http://www.01cms.com
 */

class ProgramController extends Controller
{
    public $title = '程序管理';
    public $Db;
    public $modulesPath;
    public $modules;
    public $fileListNames;

    function __construct ()
    {
        parent::__construct();
        if (! model('User')->isLogined())
        {
            redirect('admin/login?url=' . getCurUrl());
        }
        if (! model('User')->checkAuth())
        {
            exit('您的权限不足');
        }
        $this->modulesPath = APP_PATH . '/data/module';
        $this->modulesDir = BOOT_DIR . '/data/module';
        $this->Db = model('Db');
    }

    function index ()
    {
        $dh = dir($this->modulesPath);
        $fp = fopen($this->modulesPath . '/cache.php', 'w');
        ///fwrite($fp, '<?php' . "\r\n");
        while ($fileName = $dh->read())
        {
            if (eregi('\.mod$', $fileName))
            {
                $info = $this->getInfo(str_replace('.mod', '', $fileName));
                if ($info['hash'] != '')
                {
                    $this->modules[$info['hash']] = $info;
                    fwrite($fp, '$' . "modules['{$info['hash']}'] = '{$fileName}';\r\n");
                }
            }
        }
        fclose($fp);
        $dh->Close();
        $this->modules;
        $this->Load->view('smarty');
    }

    function export ($action = '', $hash = '')
    {
        $this->title = $this->title . ' => 程序导出';
        if ($action == '')
        {
            $this->Load->view('smarty');
        }
        else if ($action == 'mod')
        {
            $this->data = $this->getInfo($hash);
            $this->data['inSql'] = $this->getSystemFile($hash, 'inSql');
            $this->data['unSql'] = $this->getSystemFile($hash, 'unSql');
            $this->data['info'] = $this->getSystemFile($hash, 'info');
            $this->data['fileList'] = $this->getFileLists($hash);
            $this->Load->view('smarty', 'mod');
        }
        else if ($action == 'insert' || $action == 'update')
        {
            $data = $this->Load->post('name|名称不能为空,author|作者不能为空,contact,version,info,inSql,unSql,fileList|文件列表不能为空');
            if ($error = $this->Load->getError())
            {
                response($error);
            }
            foreach ($data as $k => $v)
            {
                $$k = stripslashes($v);
            }
            $fileList = str_replace("\r", "\n", trim($fileList));
            $fileList = trim(ereg_replace("[\n]{1,}", "\n", $fileList));
            if ($action == 'insert') $hash = md5($name . $author . $contact);
            $moduleFileName = $this->modulesPath . '/' . $hash . '.mod';
            $downloadUrl = $this->modulesDir . '/' . $hash . '.mod';
            if ($action == 'insert' && $this->moduleExists($hash))
            {
                $this->clear();
                response("同名模块已经存在！<br>如果你要更新这个模块，请先删除同名模块文件");
                exit();
            }
            $time = TIME;
            $inSql = (trim($inSql) == '') ? '' : base64_encode(trim($inSql));
            $unSql = (trim($unSql) == '') ? '' : base64_encode(trim($unSql));
            $info = (trim($info) == '') ? '' : base64_encode(trim($info));
            $modulInfo = "<module>
<baseinfo>
name={$name}
author={$author}
contact={$contact}
time={$time}
version={$version}
hash={$hash}
</baseinfo>
<systemfile>
<info>
{$info}
</info>
<inSql>
{$inSql}
</inSql>
<unSql>
{$unSql}
</unSql>
</systemfile>
";
            $fileList = explode("\n", $fileList);
            foreach ($fileList as $v)
            {
                $v = trim($v);
                if (! empty($v))
                {
                    $this->makeEncodeFileTest(ROOT_PATH, $v);
                }
            }
            $this->fileListNames = array();
            $fp = fopen($moduleFileName, 'w');
            fwrite($fp, $modulInfo);
            fwrite($fp, "<moduleFiles>\r\n");
            foreach ($fileList as $v)
            {
                $v = trim($v);
                if (! empty($v))
                {
                    $this->makeEncodeFile(ROOT_PATH, $v, $fp);
                }
            }
            $this->fileListNames = array();
            fwrite($fp, "</moduleFiles>\r\n");
            fwrite($fp, "</module>\r\n");
            fclose($fp);
            response("打包成功，【<a href='$downloadUrl' target='_blank'>下载</a>】【<a href='" . BOOT_URL . "/Program/index'>返回</a>】", true);
        }
    }

    function install ($hash = '')
    {
        $inSql = $this->getSystemfile($hash, 'inSql');
        $this->Db->query($inSql);
        $this->writeFiles($hash);
        $this->writeInfo($hash);
        response('安装成功', true);
    }

    function uninstall ($hash = '')
    {
        $unSql = $this->getSystemfile($hash, 'unSql');
        $this->Db->query($unSql);
        $this->delFiles($hash);
        $this->delInfo($hash);
        response('卸载成功', true);
    }

    function getFileLists ($hash)
    {
        $fileLists = array();
        $moduleFile = $this->modulesPath . '/' . $this->getHashFile($hash);
        $fp = fopen($moduleFile, 'r');
        $i = 0;
        while (! feof($fp))
        {
            $line = fgets($fp, 1024);
            if (preg_match("/^[\s]{0,}<file/i", $line))
            {
                $i ++;
                $line = trim(preg_replace("/[><]/", "", $line));
                preg_match("/type=['\"]([\w]+)['\"][\s]{0,}name=['\"]([\w\/\.]+)['\"]/i", $line, $match);
                if(isset($match[1]))
                {
                    $fileLists[$i]['type'] = $match[1];
                    $fileLists[$i]['name'] = $match[2];
                }
            }
        }
        fclose($fp);
        return $fileLists;
    }

    function getInfo ($hash)
    {
        $fileName = $this->modulesPath . '/' . $this->getHashFile($hash);
        $start = 0;
        $info = array();
        if (file_exists($this->modulesPath . '/' . $hash . '.html'))
        {
            $info['isInstall'] = TRUE;
        }
        else
        {
            $info['isInstall'] = FALSE;
        }
        $info['name'] = $info['author'] = $info['time'] = $info['url'] = $info['hash'] = '';
        $info['fileName'] = $fileName;
        $info['filesize'] = filesize($fileName) / 1024;
        $info['filesize'] = number_format($info['filesize'], 2, '.', '') . ' Kb';
        $fp = fopen($fileName, 'r');
        $n = 0;
        while (! feof($fp))
        {
            $n ++;
            if ($n > 50)
            {
                break;
            }
            $line = fgets($fp, 256);
            if ($start == 0)
            {
                if (preg_match("/<baseinfo/is", $line))
                {
                    $start = 1;
                }
            }
            else
            {
                if (preg_match("/<\/baseinfo/is", $line))
                {
                    break;
                }
                $line = trim($line);
                list ($skey, $svalue) = explode('=', $line);
                $skey = trim($skey);
                $info[$skey] = $svalue;
            }
        }
        fclose($fp);
        return $info;
    }

    function clear ()
    {
        unset($this->modules);
        unset($this->fileList);
        unset($this->fileListNames);
    }

    function getHashFile ($hash)
    {
        return $hash . '.mod';
    }

    function moduleExists ($hash)
    {
        $moduleFile = $this->modulesPath . '/' . $this->getHashFile($hash);
        if (file_exists($moduleFile) && ! is_dir($moduleFile))
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    //
    //测试某文件的文件夹是否创建
    //
    function testDir ($filename)
    {
        $fs = explode('/', $filename);
        $fn = count($fs) - 1;
        $ndir = '';
        for ($i = 0; $i < $fn; $i ++)
        {
            if ($ndir != '')
                $ndir = $ndir . '/' . $fs[$i];
            else
                $ndir = $fs[$i];
            $rs = @is_dir($ndir);
            if (! $rs)
            {
                @mkdir($ndir, 664);
                @chmod($ndir, 664);
            }
        }
        return true;
    }

    //
    //获取某个目录或文件的打包数据
    //
    function makeEncodeFile ($basedir, $f, $fp)
    {
        // $this->fileListNames = array();
        $this->makeEncodeFileRun($basedir, $f, $fp);
        return true;
    }

    //
    //测试目标文件
    //
    function makeEncodeFileTest ($basedir, $f)
    {
        // $this->fileListNames = array();
        $this->makeEncodeFileRunTest($basedir, $f);
        return true;
    }

    //
    //检测某个目录或文件的打包数据，递归
    //
    function makeEncodeFileRunTest ($basedir, $f)
    {
        $filename = $basedir . '/' . $f;
        if (isset($this->fileListNames[$f]))
        {
            return;
        }
        else if (eregi("Thumbs\.db", $f))
        {
            return;
        }
        else
        {
            $this->fileListNames[$f] = 1;
        }
        $fileList = '';
        if (! file_exists($filename))
        {
            showMsg("文件或文件夹: {$filename} 不存在，无法进行编译!");
            exit();
        }
        if (is_dir($filename))
        {
            $dh = dir($filename);
            while ($filename = $dh->read())
            {
                if ($filename[0] == '.' || strtolower($filename) == 'cvs')
                {
                    continue;
                }
                $nfilename = $f . '/' . $filename;
                $this->makeEncodeFileRunTest($basedir, $nfilename);
            }
        }
    }

    //
    //获取个目录或文件的打包数据，递归
    //
    function makeEncodeFileRun ($basedir, $f, $fp)
    {
        $filename = $basedir . '/' . $f;
        if (isset($this->fileListNames[$f]))
        {
            return;
        }
        else if (eregi("Thumbs\.db", $f))
        {
            return;
        }
        else
        {
            $this->fileListNames[$f] = 1;
        }
        $fileList = '';
        if (is_dir($filename))
        {
            $fileList .= "<file type='dir' name='$f'>\r\n";
            $fileList .= "</file>\r\n";
            fwrite($fp, $fileList);
            $dh = dir($filename);
            while ($filename = $dh->read())
            {
                if ($filename[0] == '.' || strtolower($filename) == 'cvs')
                    continue;
                $nfilename = $f . '/' . $filename;
                $this->makeEncodeFileRun($basedir, $nfilename, $fp);
            }
        }
        else
        {
            $fileList .= "<file type='file' name='$f'>\r\n";
            $fileList .= $this->getEncodeFile($filename);
            $fileList .= "\r\n</file>\r\n";
            fwrite($fp, $fileList);
        }
    }

    function GetEncodeFile ($filename, $isremove = false)
    {
        $fp = fopen($filename, 'r') or die("文件 {$filename} 不存在或不可读!");
        $str = @fread($fp, filesize($filename));
        fclose($fp);
        if ($isremove)
            @unlink($filename);
        if (! empty($str))
            return base64_encode($str);
        else
            return '';
    }

    function delFiles ($hash)
    {
        $moduleFile = $this->modulesPath . '/' . $this->getHashFile($hash);
        $fp = fopen($moduleFile, 'r');
        $i = 0;
        while (! feof($fp))
        {
            $line = fgets($fp, 1024);
            if (preg_match("/^[\s]{0,}<file/i", $line))
            {
                $i ++;
                $line = trim(preg_replace("/[><]/", "", $line));
                preg_match("/type=['\"]([\w]+)['\"][\s]{0,}name=['\"]([\w\/\.]+)['\"]/i", $line, $match);
                if (! isset($match[1]))
                {
                    continue;
                }
                $filetype = $match[1];
                $filename = ROOT_PATH . $match[2];
                if ($filetype == 'dir')
                {
                    clearDirs($filename);
                    @rmdir($filename);
                }
                else
                {
                    @unlink($filename);
                }
            }
        }
        fclose($fp);
        $this->delInfo($hash);
        return true;
    }

    //把模块包里的文件写入服务器
    function writeFiles ($hash, $isreplace = 1)
    {
        $moduleFile = $this->modulesPath . '/' . $this->getHashFile($hash);
        $fp = fopen($moduleFile, 'r');
        $i = 0;
        while (! feof($fp))
        {
            $line = fgets($fp, 1024);
            if (preg_match("/^[\s]{0,}<file/i", $line))
            {
                $i ++;
                $line = trim(preg_replace("/[><]/", "", $line));
                preg_match("/type=['\"]([\w]+)['\"][\s]{0,}name=['\"]([\w\/\.]+)['\"]/i", $line, $match);
                if (! isset($match[1]))
                {
                    continue;
                }
                $filetype = $match[1];
                $filename = ROOT_PATH . $match[2];
                if ($filetype == 'dir')
                {
                    if (! is_dir($filename))
                    {
                        @mkdir($filename, 777);
                    }
                    @chmod($filename, 777);
                }
                else
                {
                    $this->testDir($filename);
                    if ($isreplace == 0)
                    {
                        continue;
                    }
                    if ($isreplace == 3)
                    {
                        if (is_file($filename))
                        {
                            $copyname = @preg_replace("/([^\/]{1,}$)/", "bak-$1", $filename);
                            @copy($filename, $copyname);
                        }
                    }
                    if (! empty($filename))
                    {
                        $fw = fopen($filename, 'w');
                        $ct = '';
                        while (! feof($fp))
                        {
                            $l = fgets($fp, 1024);
                            if (preg_match("/^[\s]{0,}<\/file/i", trim($l)))
                            {
                                break;
                            }
                            $ct .= $l;
                        }
                        $ct = base64_decode($ct);
                        fwrite($fw, $ct);
                        fclose($fw);
                    }
                }
            }
        }
        fclose($fp);
        return true;
    }

    function getSystemFile ($hash, $ntype, $enCode = true)
    {
        $this->getInfo($hash, $ntype);
        $start = false;
        $fileName = $this->modulesPath . '/' . $this->getHashFile($hash);
        $fp = fopen($fileName, 'r');
        $okdata = '';
        while (! feof($fp))
        {
            $line = fgets($fp, 1024);
            if (! $start)
            {
                if (eregi("<{$ntype}", $line))
                    $start = true;
            }
            else
            {
                if (eregi("</{$ntype}", $line))
                    break;
                $okdata .= $line;
                unset($line);
            }
        }
        fclose($fp);
        $okdata = trim($okdata);
        if (! empty($okdata) && $enCode)
            $okdata = base64_decode($okdata);
        return $okdata;
    }

    function writeInfo ($hash)
    {
        $fileName = $hash . ".html";
        $fname = $this->modulesPath . '/' . $fileName;
        $filect = $this->getSystemFile($hash, 'info');
        $fp = fopen($fname, 'w');
        fwrite($fp, $filect);
        fclose($fp);
        return $fileName;
    }

    function delInfo ($hash)
    {
        $fileName = $hash . ".html";
        $fname = $this->modulesPath . '/' . $fileName;
        @unlink($fname);
    }
}
